#include "constants.h"
// by Xeno
// Commented/Edited by Tyrghen

g_bCommonFuncsCompiled = false;

// This function receives an array name as first parameter and an array as second.
// It will simply place all values of the second parameter at the end of the array represented by the first parameter
//
// Param 1: Target Array Name
// Param 2: Array of values to add
// Return : Merged array
XfArrayPushStack = {
	Private ["_aArray","_aValues"];
	_aArray = _this select 0;
	_aValues = _this select 1;
	{(_aArray) set [count (_aArray), _x]} foreach (_aValues);
	(_aArray)
};

// get a random numer, floored
// parameters: number
// example: _randomint = 30 call XfRandomFloor;
XfRandomFloor = {floor (random _this)};

// shuffles the content of an array
// parameters: array
// example: _myrandomarray = _myNormalArray call XfRandomArray;
XfRandomArray = {
	private ["_ar","_ran_array","_this"];
	_ar =+ _this;
	_ran_array = [];
	while {count _ar > 0} do {
		_ran = (count _ar) call XfRandomFloor;
		_ran_array set [count _ran_array, _ar select _ran];
		_ar set [_ran, "xfXX_del"];
		_ar = _ar - ["xfXX_del"];
	};
	_ran_array
};

// creates an array with count random indices
// parameters: int (number of entries)
// example: _myrandomindexarray = _numberentries call XfRandomIndexArray;
XfRandomIndexArray = {
	private ["_count","_ran_array"];
	_count = _this;
	_ran_array = [];
	for "_i" from 0 to (_count - 1) do {_ran_array set [count _ran_array, _i]};
	_ran_array = _ran_array call XfRandomArray;
	_ran_array
};

// Returns an array with all the names of the possible unit types contained in a predefined army group.
// This is what you'll get when you place a group in the Mission Editor. Ex: US_MGSPlatoon
XfGetConfigGroup = {
	private ["_side", "_type", "_typeunits", "_typegroup", "_ret", "_config", "_i", "_cfgn"];
	_side = _this select 0; // "West"
	_type = _this select 1; // "USMC"
	_typeunits = _this select 2; // "Infantry"
	_typegroup = _this select 3;  // "USMC_InfSquad"
	_ret = [];
	
	_config = (configFile >> "CfgGroups" >> _side >> _type >> _typeunits >> _typegroup);
	if (isClass _config) then {
		for "_i" from 0 to (count _config - 1) do {
			_cfgn = _config select _i;
			if (isClass _cfgn) then {_ret set [count _ret, getText (_cfgn >> "vehicle")]};
		};
	};
	_ret
};

// direction from one object to another
// parameters: object1, object2
// example: _dir = [tank1, apc1] call XfDirToObj;
XfDirToObj = {
	private ["_o1","_o2","_deg"];
	_o1 = _this select 0;_o2 = _this select 1;
	_deg = ((position _o2 select 0) - (position _o1 select 0)) atan2 ((position _o2 select 1) - (position _o1 select 1));
	if (_deg < 0) then {_deg = _deg + 360};
	_deg
};

// ground distance between two objects of positions
// parameters: object1/position1, object2/position2
// example: _dist = [tank1, [1023,1456,324]] call XfDistTo;
XfDistTo = {
	private ["_o1","_o2","_dist"];
	_o1 = _this select 0;_o2 = _this select 1;
	if (typename _o1 != "ARRAY") then {_o1 = position _o1};
	if (typename _o2 != "ARRAY") then {_o2 = position _o2};
	_o1 set [2,0];
	_o2 set [2,0];
	_dist = _o1 distance _o2;
	_dist;
};

// get a random number, floored, from count array
// parameters: array
// example: _randomarrayint = _myarray call XfRandomFloorArray;
XfRandomFloorArray = {floor (random (count _this))};

// get a random item from an array
// parameters: array
// example: _randomval = _myarray call XfRandomArrayVal;
XfRandomArrayVal = {_this select (_this call XfRandomFloorArray)};

// get a random numer, ceiled
// parameters: number
// example: _randomint = 30 call XfRandomCeil;
XfRandomCeil = {ceil (random _this)};

// returns the number of human players currently playing a mission in MP
XPlayersNumber = {
	// (playersNumber east + playersNumber west + playersNumber resistance + playersNumber civilian);
	_result = 1;
	if (isMultiplayer) then {
		_result = 0;
		{ if (isPlayer _x) then {_result = _result +1;};
		}foreach playableUnits;
	};
	_result;
};

// gets a random number in a specific range
// parameters: number from, number to (second number must be greater than first)
// example: _random_number = [30,150] call XfGetRandomRange;
XfGetRandomRange = {
	private ["_num1","_num2","_ra"];
	_num1 = _this select 0;_num2 = _this select 1;
	_ra = _num2 - _num1;
	_ra = random _ra;
	(_num1 + _ra)
};

// gets a random integer number in a specific range
// parameters: integer from, integer to (second number must be greater than first)
// example: _random_integer = [30,150] call XfGetRandomRangeInt;
XfGetRandomRangeInt = {
	private ["_num1","_num2","_ra"];
	_num1 = _this select 0;_num2 = _this select 1;
	if (_num1 > _num2) then {_num1 = _this select 1;_num2 = _this select 0};
	_ra = _num2 - _num1;
	_ra = _ra call XfRandomFloor;
	(_num1 + _ra)
};

// compares two arrays, if equal returns true, if not false
// parameters: array1, array2
// example: _isequal = [array1, array2] call XfArrayCompare;
XfArrayCompare = {if (str (_this select 0) == str (_this select 1)) then {true} else {false}};

// get height of object
// parameters: object (no brackets)
// _height = tank1 call XfGetHeight;
XfGetHeight = {position _this select 2};

// set only height of an object
// parameters: object, height
// example: [unit1, 30] call XfSetHeight;
XfSetHeight = {(this select 0) setPos [position (this select 0) select 0, position (this select 0) select 1, (_this select 1)]};

// set only ASL height of an object
// parameters: object, height
// example: [unit1, 30] call XfSetASLHeight;
XfSetASLHeight = {(this select 0) setPosASL [position (this select 0) select 0, position (this select 0) select 1, (_this select 1)]};

// set only ATL height of an object
// parameters: object, height
// example: [unit1, 30] call XfSetATLHeight;
XfSetATLHeight = {(this select 0) setPosATL [position (this select 0) select 0, position (this select 0) select 1, (_this select 1)]};

// get x position of an object
// parameters: object (no brackets)
// _posx = tank1 call XfGetPosX;
XfGetPosX = {position _this select 0};

// set only x position of an object
// parameters: object, x
// example: [unit1, 30] call XfSetPosX;
XfSetPosX = {(this select 0) setPos [(_this select 1), position (this select 0) select 1, position (this select 0) select 2]};

// get y position of an object
// parameters: object (no brackets)
// _posy = tank1 call XfGetPosY;
XfGetPosY = {position _this select 1};

// set only y position of an object
// parameters: object, y
// example: [unit1, 30] call XfSetPosY;
XfSetPosY = {(this select 0) setPos [position (this select 0) select 0, (_this select 1), position (this select 0) select 2]};

// Set both X and Y position without changing Z.
XfSetPosXY = {(this select 0) setPos [(_this select 1), (_this select 2), position (this select 0) select 2]};

XfIsRectangle = {
	if (count _this <= XF_SHAPE_RECTANGLE) then {_this set [XF_SHAPE_RECTANGLE, false];};
	(_this select XF_SHAPE_RECTANGLE);
};

// [_position, _shape_array] call XfPointInShape;
XfPointInShape = {
	private ["_point","_shape","_inside"];
	_point = _this select 0;
	_shape = _this select 1;
	_inside = false;
	if (_shape call XfIsRectangle) then {
		_inside = [_point, (_shape select XF_SHAPE_CENTER), (_shape select XF_SHAPE_WIDTH), (_shape select XF_SHAPE_HEIGHT), (_shape select XF_SHAPE_ANGLE)] call XfPointInSquare;
	} else {
		_inside = [_point, (_shape select XF_SHAPE_CENTER), (_shape select XF_SHAPE_WIDTH)] call XfPointInCircle;
	};
	_inside;
};

// [_position, _shape_array] call XfPointInShapeArray;
XfPointInShapeArray = {
	private ["_point","_shape_array","_inside"];
	_point = _this select 0;
	if (count _this > 0) then {
		_shape_array = _this select 1;
	};
	_inside = false;
	// diag_log Format["XfPointInShapeArray : %1",_this];
	if (!isnil "_shape_array") then {
		if (typeName _shape_array == "ARRAY") then {
			if (count _shape_array > 0) then
			{
				{
					if (_inside) exitWith {};
					if (_x call XfIsRectangle) then {
						_inside = [_point, (_x select XF_SHAPE_CENTER), (_x select XF_SHAPE_WIDTH), (_x select XF_SHAPE_HEIGHT), (_x select XF_SHAPE_ANGLE)] call XfPointInSquare;
					} else {
						_inside = [_point, (_x select XF_SHAPE_CENTER), (_x select XF_SHAPE_WIDTH)] call XfPointInCircle;
					};
				} foreach _shape_array;
			};
		};
	};
	_inside;
};

// [_shape_array,_empty_radius] call XfGetRanPointShapeBig;
XfGetRanPointShapeBig = {
	private ["_point","_shape"];
	_point = [];
	_empty_radius = "default";
	_shape = _this select 0;
	if (count _this > 1) then {_empty_radius = _this select 1};
	if (_shape call XfIsRectangle) then {
		_point = [(_shape select XF_SHAPE_CENTER), (_shape select XF_SHAPE_WIDTH), (_shape select XF_SHAPE_HEIGHT), (_shape select XF_SHAPE_ANGLE),_empty_radius] call XfGetRanPointSquareBig;
	} else {
		_point = [(_shape select XF_SHAPE_CENTER), (_shape select XF_SHAPE_WIDTH),_empty_radius] call XfGetRanPointCircleBig;
	};
	_point;
};


// Returns true if the point is inside the circle.
// ex: [_point, _center, _radius] call XfPointInCircle;
// ex: [_point, [_center, _radius]] call XfPointInCircle;
XfPointInCircle = {
	private ["_point","_center","_radius","_inside"];
	_inside = false;
	_point = _this select 0;
	if (count _this == 2) then {
		_center = (_this select 1) select 0;
		_radius = (_this select 1) select 1;
	} else {
		_center = _this select 1;
		_radius = _this select 2;
	};
	_inside = ((_point distance _center) < _radius);
	_inside;
};

// Returns true if the point is inside the rectangle.
// ex: [_point, _center, _width, _height, _angle] call XfPointInSquare;
XfPointInSquare = {
	private ["_point","_center","_width","_height","_angle","_dist","_dir","_corrected_angle","_cx","_cy","_inside"];
	_inside = false;
	_point = _this select 0;
	_center = _this select 1;
	_width = _this select 2;
	_height = _this select 3;
	_angle = _this select 4;
	_dist = (_point distance _center);
	_dir = (([_center, _point] call XfDirTo) - 90);
	_corrected_angle = _dir - _angle;
	_cx = abs(_dist * (cos _corrected_angle));
	_cy = abs(_dist * (sin _corrected_angle));
	_inside = ((_cx <= (_width / 2)) && (_cy <= (_height / 2)));
	// diag_log Format["(%1)[%2]: %3",diag_tickTime,"XfPointInSquare",[_this,_dist,_dir,_cx,_cy]];
	_inside;
};

// get a random point inside a circle
// parameters:
// center position, radius of the circle, [minimum distance of center]
// example: _random_point = [position trigger1, 200] call XfGetRanPointCircle;
// example: _random_point = [position trigger1, 200, 100] call XfGetRanPointCircle;
XfGetRanPointCircle = {
	private ["_center", "_radius", "_center_x", "_center_y", "_ret_val", "_co", "_angle", "_x1", "_y1", "_helper"];
	_center = _this select 0;_radius = _this select 1;
	_min_dist = 0;
	if (count _this > 2) then { _min_dist = _this select 2; };
	if (_radius < _min_dist) then { _min_dist = 0; };
	_center_x = _center select 0;_center_y = _center select 1;
	_ret_val = [];_co = 0;
	while {count _ret_val == 0 && _co < 100} do {
		_angle = floor (random 360);
		_randradius = _min_dist + random(_radius - _min_dist);
		_x1 = _center_x - (_randradius * sin _angle);
		_y1 = _center_y - (_randradius * cos _angle);
		if (!(surfaceiswater [_x1, _y1])) then {
			_helper = "RoadCone" createVehicleLocal [_x1,_y1,0];
			if (!(surfaceIsWater [getPosASL _helper select 0, getPosASL _helper select 1])) then {
				_slope = [position _helper, 5] call XfGetSlope;
				if (_slope < 0.5) then {_ret_val = [getPosASL _helper select 0, getPosASL _helper select 1,0]};
			};
			deleteVehicle _helper;
		};
		if (count _ret_val == 0) then {_co = _co + 1};
	};
	_ret_val
};

// no slope check, for patrolling
XfGetRanPointCircleOld = {
	private ["_center", "_radius", "_center_x", "_center_y", "_ret_val", "_co", "_angle", "_x1", "_y1", "_helper"];
	_center = _this select 0;_radius = _this select 1;
	_center_x = _center select 0;_center_y = _center select 1;
	_ret_val = [];_co = 0;
	while {count _ret_val == 0 && _co < 100} do {
		_angle = floor (random 360);
		_x1 = _center_x - ((random _radius) * sin _angle);
		_y1 = _center_y - ((random _radius) * cos _angle);
		if (!(surfaceiswater [_x1, _y1])) then {_ret_val = [_x1, _y1, 0]};
		if (count _ret_val == 0) then {_co = _co + 1};
	};
	_ret_val
};

// no slope or water check, for air vehicle
XfGetRanPointCircleAir = {
	private ["_center", "_radius", "_center_x", "_center_y", "_ret_val","_angle", "_x1", "_y1"];
	_center = _this select 0;_radius = _this select 1;
	_center_x = _center select 0;_center_y = _center select 1;
	_ret_val = [];
	_angle = floor (random 360);
	_x1 = _center_x - ((random _radius) * sin _angle);
	_y1 = _center_y - ((random _radius) * cos _angle);
	_ret_val = [_x1, _y1, 0];
	_ret_val
};

// Experimental tree identification method
XfIsTree = {
	private ["_name_array","_is_tree","_i","_char"];
	_name_array = _this;
	_is_tree = false;
	if (count _name_array > 0) then {
		For [{_i = 0},{_i < (count _name_array - 4)},{_i = _i + 1}] do {
			_char = _name_array select _i;
			if (_char == 58) then {
				If (((_name_array select (_i + 1)) == 32) AND ((_name_array select (_i + 2)) == 116) AND ((_name_array select (_i + 3)) == 95)) exitWith {_is_tree = True;};
			};
		};
	};
	_is_tree;
};

// get a random point inside a circle for bigger objects
// parameters:
// center position, radius of the circle, (optional) radius to check empty
// example: _random_point = [position trigger1, 200] call XfGetRanPointCircleBig;
XfGetRanPointCircleBig = {
	private ["_center", "_radius", "_center_x", "_center_y", "_ret_val", "_co", "_angle", "_x1", "_y1", "_nobs","_obs_found", "_helper"];
	_center = _this select 0;_radius = _this select 1;
	_center_x = _center select 0;_center_y = _center select 1;
	_empty_radius = 20;
	if (count _this > 2) then {_empty_radius = _this select 2;};
	if (typeName _empty_radius != "SCALAR") then {_empty_radius = 20; };
	if (_empty_radius < 10) then {_empty_radius = 10;};
	_ret_val = [];_co = 0;
	while {count _ret_val == 0 && _co < 100} do {
		_angle = floor (random 360);
		_x1 = _center_x - ((random _radius) * sin _angle);
		_y1 = _center_y - ((random _radius) * cos _angle);
		if (!(surfaceiswater [_x1, _y1])) then {
			// _nobs = [_x1,_y1,0] nearObjects ["Static",_empty_radius];
			// if (count _nobs == 0) then {
			_nobs = [_x1,_y1,0] nearObjects _empty_radius;
			_obs_found = false;
			{
				if (_x isKindOf "Static") exitwith {_obs_found = true;};
				if (toArray(str(_x)) call XfIsTree) exitwith {_obs_found = true;};
			} foreach _nobs;
			if (!_obs_found) then {
				_helper = "RoadCone" createVehicleLocal [_x1,_y1,0];
				if (!(surfaceIsWater [getPosASL _helper select 0, getPosASL _helper select 1])) then {
					_slope = [position _helper, 5] call XfGetSlope;
					if (_slope < 0.5 && !(isOnRoad (position _helper))) then {_ret_val = [getPosASL _helper select 0,getPosASL _helper select 1,0]};
				};
				deleteVehicle _helper;
			};
		};
		if (count _ret_val == 0) then {_co = _co + 1};
	};
	_ret_val
};

// get a random point at the borders of a circle
// parameters:
// center position, radius of the circle
// example: _random_point = [position trigger1, 200] call XfGetRanPointCircleOuter;
XfGetRanPointCircleOuter = {
	private ["_center", "_radius", "_center_x", "_center_y", "_ret_val", "_co", "_angle", "_x1", "_y1", "_helper"];
	_center = _this select 0;_radius = _this select 1;
	_center_x = _center select 0;_center_y = _center select 1;
	_ret_val = [];_co = 0;
	while {count _ret_val == 0 && _co < 100} do {
		_angle = floor (random 360);
		_x1 = _center_x - (_radius * sin _angle);
		_y1 = _center_y - (_radius * cos _angle);
		if (!(surfaceiswater [_x1, _y1])) then {
			_helper = "RoadCone" createVehicleLocal [_x1,_y1,0];
			if (!(surfaceIsWater [getPosASL _helper select 0, getPosASL _helper select 1])) then {
				_slope = [position _helper, 5] call XfGetSlope;
				if (_slope < 0.5) then {_ret_val = [getPosASL _helper select 0, getPosASL _helper select 1, 0]};
			};
			deleteVehicle _helper;
		};
		if (count _ret_val == 0) then {_co = _co + 1};
	};
	_ret_val
};

// get a random point inside a square
// parameters:
// center position, a and b (like in triggers), angle
// example: _random_point  = [position trigger2, 200, 300, 30] call XfGetRanPointSquare;
XfGetRanPointSquare = {
	private ["_pos", "_a", "_b", "_angle", "_centerx", "_centery", "_leftx", "_lefty", "_width", "_height", "_ret_val", "_co", "_px1", "_py1", "_radius", "_atan", "_x1", "_y1", "_helper"];
	_pos = _this select 0;_a = _this select 1;_b = _this select 2;_angle = _this select 3;
	_centerx = _pos select 0;_centery = _pos select 1;_leftx = _centerx - _a;_lefty = _centery - _b;
	_width = 2 * _a;_height = 2 * _b;_ret_val = [];_co = 0;
	while {count _ret_val == 0 && _co < 100} do {
		_px1 = _leftx + random _width; _py1 = _lefty + random _height;
		_radius = _pos distance [_px1,_py1];
		_atan = (_centerx - _px1) atan2 (_centery - _py1);
		_x1 = _centerx - (_radius * sin (_atan + _angle));
		_y1 = _centery - (_radius * cos (_atan + _angle));
		if (!(surfaceiswater [_x1, _y1])) then {
			_helper = "RoadCone" createVehicleLocal [_x1,_y1,0];
			if (!(surfaceIsWater [getPosASL _helper select 0, getPosASL _helper select 1])) then {
				_slope = [position _helper, 5] call XfGetSlope;
				if (_slope < 0.5) then {_ret_val = [getPosASL _helper select 0, getPosASL _helper select 1, 0]};
			};
			deleteVehicle _helper;
		};
		if (count _ret_val == 0) then {_co = _co + 1};
	};
	_ret_val
};

// get a random point inside a square
// parameters:
// center position, width and height, angle
// example: _random_point  = [position trigger2, 200, 300, 30] call XfGetRanPointSquareBig;
XfGetRanPointSquareBig = {
	private ["_pos", "_a", "_b", "_angle", "_centerx", "_centery", "_leftx", "_lefty", "_width", "_height", "_ret_val", "_co", "_px1", "_py1", "_radius", "_atan", "_x1", "_y1", "_helper"];
	_pos = _this select 0;_width = _this select 1;_height = _this select 2;_angle = _this select 3;
	_centerx = _pos select 0;_centery = _pos select 1;_leftx = _centerx - (_width / 2);_lefty = _centery - (_height / 2);
	_ret_val = [];_co = 0;
	_empty_radius = 20;
	if (count _this > 4) then {_empty_radius = _this select 4};
	if (typeName _empty_radius != "SCALAR") then {_empty_radius = 20; };
	while {count _ret_val == 0 && _co < 100} do {
		_px1 = _leftx + random _width; _py1 = _lefty + random _height;
		_radius = _pos distance [_px1,_py1];
		_atan = (_centerx - _px1) atan2 (_centery - _py1);
		_x1 = _centerx - (_radius * sin (_atan + _angle));
		_y1 = _centery - (_radius * cos (_atan + _angle));
		if (!(surfaceiswater [_x1, _y1])) then {
			_nobs = [_x1,_y1,0] nearObjects _empty_radius;
			_obs_found = false;
			{
				if (_x isKindOf "Static") exitwith {_obs_found = true;};
				if (toArray(str(_x)) call XfIsTree) exitwith {_obs_found = true;};
			} foreach _nobs;
			if (!_obs_found) then {
				_helper = "RoadCone" createVehicleLocal [_x1,_y1,0];
				if (!(surfaceIsWater [getPosASL _helper select 0, getPosASL _helper select 1])) then {
					_slope = [position _helper, 5] call XfGetSlope;
					if (_slope < 0.5) then {_ret_val = [getPosASL _helper select 0, getPosASL _helper select 1, 0]};
				};
				deleteVehicle _helper;
			};	
		};
		if (count _ret_val == 0) then {_co = _co + 1};
	};
	_ret_val
};

// no slope check, for patrolling
XfGetRanPointSquareOld = {
	private ["_pos", "_a", "_b", "_angle", "_centerx", "_centery", "_leftx", "_lefty", "_width", "_height", "_ret_val", "_co", "_px1", "_py1", "_radius", "_atan", "_x1", "_y1"];
	_pos = _this select 0;_a = _this select 1;_b = _this select 2;_angle = _this select 3;
	_centerx = _pos select 0;_centery = _pos select 1;_leftx = _centerx - _a;_lefty = _centery - _b;
	_width = 2 * _a;_height = 2 * _b;_ret_val = [];_co = 0;
	while {count _ret_val == 0 && _co < 100} do {
		_px1 = _leftx + random _width; _py1 = _lefty + random _height;
		_radius = _pos distance [_px1,_py1];
		_atan = (_centerx - _px1) atan2 (_centery - _py1);
		_x1 = _centerx - (_radius * sin (_atan + _angle));
		_y1 = _centery - (_radius * cos (_atan + _angle));
		if (!(surfaceiswater [_x1, _y1])) then {_ret_val = [_x1, _y1, 0]};
		if (count _ret_val == 0) then {_co = _co + 1};
	};
	_ret_val
};

// get a random point at the borders of a square
// parameters:
// center position, a and b (like in triggers), angle
// example: _random_point  = [position trigger2, 200, 300, 30] call XfGetRanPointSquareOuter;
XfGetRanPointSquareOuter = {
	private ["_pos", "_a", "_b", "_angle", "_centerx", "_centery", "_leftx", "_lefty", "_width", "_height", "_ret_val", "_co", "_px1", "_py1", "_radius", "_atan", "_x1", "_y1", "_helper"];
	_pos = _this select 0;_a = _this select 1;_b = _this select 2;_angle = _this select 3;
	_centerx = _pos select 0;_centery = _pos select 1;_leftx = _centerx - _a;_lefty = _centery - _b;
	_width = 2 * _a;_height = 2 * _b;_ret_val = [];_co = 0;
	while {count _ret_val == 0 && _co < 100} do {
		_rside = floor (random 4);
		_px1 = switch (_rside) do {
			case 0: {_leftx + random _width};
			case 1: {_leftx + _width};
			case 2: {_leftx + random _width};
			case 3: {_leftx};
		};
		_py1 = switch (_rside) do {
			case 0: {_lefty + _height};
			case 1: {_lefty + random _height};
			case 2: {_lefty};
			case 3: {_lefty + random _height};
		};
		_radius = _pos distance [_px1,_py1];
		_atan = (_centerx - _px1) atan2 (_centery - _py1);
		_x1 = _centerx - (_radius * sin (_atan + _angle));
		_y1 = _centery - (_radius * cos (_atan + _angle));
		if (!(surfaceiswater [_x1, _y1])) then {
			_helper = "RoadCone" createVehicleLocal [_x1,_y1,0];
			if (!(surfaceIsWater [getPosASL _helper select 0, getPosASL _helper select 1])) then {
				_slope = [position _helper, 5] call XfGetSlope;
				if (_slope < 0.5) then {_ret_val = [getPosASL _helper select 0, getPosASL _helper select 1,0]};
			};
			deleteVehicle _helper;
		};
		if (count _ret_val == 0) then {_co = _co + 1};
	};
	_ret_val
};

// get a random point at the borders of a square
// parameters:
// center position, a and b (like in triggers), angle
// example: _random_point  = [position trigger2, 200, 300, 30] call XfGetRanPointSquareOuter;
XfGetRanPointSquareOuter = {
	private ["_pos", "_a", "_b", "_angle", "_centerx", "_centery", "_leftx", "_lefty", "_width", "_height", "_ret_val", "_co", "_px1", "_py1", "_radius", "_atan", "_x1", "_y1", "_helper"];
	_pos = _this select 0;_a = _this select 1;_b = _this select 2;_angle = _this select 3;
	_centerx = _pos select 0;_centery = _pos select 1;_leftx = _centerx - _a;_lefty = _centery - _b;
	_width = 2 * _a;_height = 2 * _b;_ret_val = [];_co = 0;
	while {count _ret_val == 0 && _co < 100} do {
		_rside = floor (random 4);
		_px1 = switch (_rside) do {
			case 0: {_leftx + random _width};
			case 1: {_leftx + _width};
			case 2: {_leftx + random _width};
			case 3: {_leftx};
		};
		_py1 = switch (_rside) do {
			case 0: {_lefty + _height};
			case 1: {_lefty + random _height};
			case 2: {_lefty};
			case 3: {_lefty + random _height};
		};
		_radius = _pos distance [_px1,_py1];
		_atan = (_centerx - _px1) atan2 (_centery - _py1);
		_x1 = _centerx - (_radius * sin (_atan + _angle));
		_y1 = _centery - (_radius * cos (_atan + _angle));
		if (!(surfaceiswater [_x1, _y1])) then {
			_helper = "RoadCone" createVehicleLocal [_x1,_y1,0];
			if (!(surfaceIsWater [getPosASL _helper select 0, getPosASL _helper select 1])) then {
				_slope = [position _helper, 5] call XfGetSlope;
				if (_slope < 0.5) then {_ret_val = [getPosASL _helper select 0, getPosASL _helper select 1,0]};
			};
			deleteVehicle _helper;
		};
		if (count _ret_val == 0) then {_co = _co + 1};
	};
	_ret_val
};

// get a random point at the borders of the current island for spawning air vehicles (no slope check, no is water check, etc)
// parameters:
// center position, left x, left y, width, height, angle (optional)
XfGetRanPointOuterAir = {
	private ["_pos", "_centerx", "_centery", "_leftx", "_lefty", "_width", "_height", "_rside", "_px1", "_py1", "_radius", "_atan", "_x1", "_y1"];
	_pos = getArray (configFile >> "CfgWorlds" >> worldName >> "centerPosition");
	_centerx = _pos select 0; _centery = _pos select 1;
	_leftx = 250;_lefty = 250;
	_width = (2 * (_pos select 0)) - 500;
	_height = (2 * (_pos select 1)) - 500;
	_rside = floor (random 4);
	_px1 = switch (_rside) do {
		case 0: {_leftx + random _width};
		case 1: {_leftx + _width};
		case 2: {_leftx + random _width};
		case 3: {_leftx};
	};
	_py1 = switch (_rside) do {
		case 0: {_lefty + _height};
		case 1: {_lefty + random _height};
		case 2: {_lefty};
		case 3: {_lefty + random _height};
	};
	_radius = _pos distance [_px1,_py1,_pos select 2];
	_atan = (_centerx - _px1) atan2 (_centery - _py1);
	_x1 = _centerx - (_radius * sin _atan);
	_y1 = _centery - (_radius * cos _atan);
	[_x1, _y1, 300]
};

XfWorldBoundsCheck = {
	private "_pos";
	_pos = _this;
	if (_pos select 0 < 0) then {_pos set [0, 400]};
	if (_pos select 1 < 0) then {_pos set [1, 400]};
	if (_pos select 0 > ((d_island_center select 0) - 2) * 2) then {_pos set [0, ((d_island_center select 0) * 2) - 100]};
	if (_pos select 1 > ((d_island_center select 1) - 2) * 2) then {_pos set [1, ((d_island_center select 1) * 2) - 100]};
	_pos
};

// get displayname of an object
// parameters: type of object (string), what (0 = CfgVehicles, 1 = CfgWeapons, 2 = CfgMagazines)
// example: _dispname = ["UAZ", 0] call XfGetDisplayName;
XfGetDisplayName = {
	private ["_obj_name", "_obj_kind", "_cfg"];
	_obj_name = _this select 0;_obj_kind = _this select 1;
	_cfg = switch (_obj_kind) do {case 0: {"CfgVehicles"};case 1: {"CfgWeapons"};case 2: {"CfgMagazines"};};
	getText (configFile >> _cfg >> _obj_name >> "displayName")
};

// Returns the name of the Vehicle given in the "Name" field
// If no name is available, a name is created
XfGetVehicleName = {
	private ["_vVehicle", "_sVehicleName"];
	_sVehicleName = "";
	_vVehicle = _this;
	If (!isNil("_vVehicle")) then {
		_sVehicleName = (if (alive _this ) then { name _this; } else { ""; });
		If ((_sVehicleName == "Error: No unit") Or (_sVehicleName == "Error: No vehicle")) then {
			_sVehicleName = "";
		};
		If (_sVehicleName == "") then {
			_sVehicleName = Format["%1%2%3",(typeof _vVehicle), (getPos _vVehicle select 0), (getPos _vVehicle select 1)];
		};
	};
	_sVehicleName
};

// from warfare
// Returns an average slope value of terrain within passed radius.
// a little bit modified. no need to create a "global" logic, local is enough, etc
// parameters: position, radius
// example: _slope = [the_position, the_radius] call XfGetSlope;
if (isNil "X_SlopeObject") then {X_SlopeObject = "HeliHEmpty" createVehicleLocal [0,0,0]};
XfGetSlope = {
	private ["_position", "_radius", "_centerHeight", "_height", "_direction", "_count"];
	_position = _this select 0;_radius = _this select 1;
	X_SlopeObject setPos _position;
	_centerHeight = getPosASL X_SlopeObject select 2;
	_height = 0;_direction = 0;
	for "_count" from 0 to 7 do {
		X_SlopeObject setPos [(_position select 0)+((sin _direction)*_radius),(_position select 1)+((cos _direction)*_radius),0];
		_direction = _direction + 45;
		_height = _height + abs (_centerHeight - (getPosASL X_SlopeObject select 2));
	};
	_height / 8
};

// create a global marker, returns created marker
// parameters: marker name, marker pos, marker shape, marker color, marker size;(optional) marker text, marker dir, marker type, marker brush
// example: ["my marker",  position player, "ELLIPSE", "ColorBlue", [0.5,0.5],"My text",90,"mil_dot","",0.9] call XfCreateMarkerGlobal;
XfCreateMarkerGlobal = {
	private ["_m_name","_m_pos","_m_shape","_m_col","_m_size","_m_text","_m_dir","_m_type","_m_brush","_m_alpha"];
	_m_name = _this select 0;
	_m_pos = _this select 1;
	_m_shape = _this select 2;
	_m_col = _this select 3;
	_m_size = _this select 4;
	_m_text = (if (count _this > 5) then {_this select 5} else {""});
	_m_dir = (if (count _this > 6) then {_this select 6} else {-888888});
	_m_type = (if (count _this > 7) then {_this select 7} else {""});
	_m_brush = (if (count _this > 8) then {_this select 8} else {""});
	_m_alpha = (if (count _this > 9) then {_this select 9} else {0});
	
	_marker = createMarker [_m_name, _m_pos];
	if (_m_shape != "") then {_marker setMarkerShape _m_shape};
	if (_m_col != "") then {_marker setMarkerColor _m_col};
	if (count _m_size > 0) then {_marker setMarkerSize _m_size};
	if (_m_text != "") then {_marker setMarkerText _m_text};
	if (_m_dir != -888888) then {_marker setMarkerDir _m_dir};
	if (_m_type != "") then {_marker setMarkerType _m_type};
	if (_m_brush != "") then {_marker setMarkerBrush _m_brush};
	if (_m_alpha != 0) then {_marker setMarkerAlpha _m_alpha};
	_marker
};

// create a local marker, returns created marker
// parameters: marker name, marker pos, marker shape, marker color, marker size;(optional) marker text, marker dir, marker type, marker brush
// example: ["my marker",  position player, "ELLIPSE", "ColorBlue", [0.5,0.5]] call XfCreateMarkerLocal;
XfCreateMarkerLocal = {
	private ["_m_name","_m_pos","_m_shape","_m_col","_m_size","_m_text","_m_dir","_m_type","_m_brush","_m_alpha"];
	_m_name = _this select 0;
	_m_pos = _this select 1;
	_m_shape = _this select 2;
	_m_col = _this select 3;
	_m_size = _this select 4;
	_m_text = (if (count _this > 5) then {_this select 5} else {""});
	_m_dir = (if (count _this > 6) then {_this select 6} else {-888888});
	_m_type = (if (count _this > 7) then {_this select 7} else {""});
	_m_brush = (if (count _this > 8) then {_this select 8} else {""});
	_m_alpha = (if (count _this > 9) then {_this select 9} else {0});
	
	if (typeName _m_pos == "ARRAY") then {
		if (count _m_pos > 0) then {
			if (typeName (_m_pos select 0) == "ARRAY") then {
				_m_dir = _m_pos select 1;
				_m_pos = _m_pos select 0;
			};
		};
	};
	
	_marker = createMarkerLocal [_m_name, _m_pos];
	if (_m_shape != "") then {_marker setMarkerShapeLocal _m_shape};
	if (_m_col != "") then {_marker setMarkerColorLocal _m_col};
	if (count _m_size > 0) then {_marker setMarkerSizeLocal _m_size};
	if (_m_text != "") then {_marker setMarkerTextLocal _m_text};
	if (_m_dir != -888888) then {_marker setMarkerDirLocal _m_dir};
	if (_m_type != "") then {_marker setMarkerTypeLocal _m_type};
	if (_m_brush != "") then {_marker setMarkerBrushLocal _m_brush};
	if (_m_alpha != 0) then {_marker setMarkerAlphaLocal _m_alpha};
	_marker
};

// Updates a local marker, returns nothing
// parameters: marker name, marker pos, marker shape, marker color, marker size;(optional) marker text, marker dir, marker type, marker brush
// example: ["my marker",  position player, "ELLIPSE", "ColorBlue", [0.5,0.5]] call XfCreateMarkerLocal;
XfUpdateMarkerLocal = {
	private ["_m_name","_m_pos","_m_shape","_m_col","_m_size","_m_text","_m_dir","_m_type","_m_brush","_m_alpha"];
	_m_name = _this select 0;
	_m_pos = _this select 1;
	_m_shape = _this select 2;
	_m_col = _this select 3;
	_m_size = _this select 4;
	_m_text = (if (count _this > 5) then {_this select 5} else {""});
	_m_dir = (if (count _this > 6) then {_this select 6} else {-888888});
	_m_type = (if (count _this > 7) then {_this select 7} else {""});
	_m_brush = (if (count _this > 8) then {_this select 8} else {""});
	_m_alpha = (if (count _this > 9) then {_this select 9} else {0});
		
	if (typeName (_m_pos select 0) == "ARRAY") then {
		_m_dir = _m_pos select 1;
		_m_pos = _m_pos select 0;
	};
	
	if (_m_shape != "") then {_m_name setMarkerShapeLocal _m_shape};
	if (_m_col != "") then {_m_name setMarkerColorLocal _m_col};
	if (count _m_size > 0) then {_m_name setMarkerSizeLocal _m_size};
	if (_m_text != "") then {_m_name setMarkerTextLocal _m_text};
	if (_m_dir != -888888) then {_m_name setMarkerDirLocal _m_dir};
	if (_m_type != "") then {_m_name setMarkerTypeLocal _m_type};
	if (_m_brush != "") then {_m_name setMarkerBrushLocal _m_brush};
	if (_m_alpha != 0) then {_m_name setMarkerAlphaLocal _m_alpha};
};
//The number of alive units in an array of units passed as parameter
XfGetAliveUnits = {({alive _x} count _this)};

// The number of alive units in a Group passed as parameter
XfGetAliveUnitsGrp = {({alive _x} count (units _this))};

// The number of alive crewmen in a vehicle passed as parameter
XfGetAliveCrew = {({alive _x} count (crew _this))};

// The direction to an object or coordinates from a given object or coordinates
// Ex:  [_vecArmor, [123,321,12]] call XfDirTo
// 		[_vecArmor, player] call XfDirTo
// 		[[456,654,21], [123,321,12]] call XfDirTo
XfDirTo = {
	/************************************************************
		Direction To
		By Andrew Barron

	Parameters: [object or position 1, object or position 2]

	Returns the compass direction from object/position 1 to
	object/position 2. Return is always >=0 <360.

	Example: [player, getpos dude] call BIS_fnc_dirTo
	************************************************************/
	private ["_pos1","_pos2","_ret"];
	_pos1 = _this select 0; _pos2 = _this select 1;

	if(typename _pos1 == "OBJECT") then {_pos1 = getpos _pos1};
	if(typename _pos2 == "OBJECT") then {_pos2 = getpos _pos2};

	_ret = ((_pos2 select 0) - (_pos1 select 0)) atan2 ((_pos2 select 1) - (_pos1 select 1));
	if (_ret < 0) then {_ret = _ret + 360};
	_ret
};

// Gives the CfgVehicles name of the parachute given the faction passed as parameter either as string or as predefined variable
// Ex:  "EAST" call XfGetParachuteSide
XfGetParachuteSide = {
	private "_ret";
	_ret = if (typeName _this == "STRING") then {
		switch (_this) do {
			case "EAST": {"ParachuteEast"};
			case "WEST": {"ParachuteWest"};
			case "GUER": {"ParachuteG"};
			case "CIV": {"ParachuteC"};
		}
	} else {
		switch (_this) do {
			case east: {"ParachuteEast"};
			case west: {"ParachuteWest"};
			case resistance: {"ParachuteG"};
			case civilian: {"ParachuteC"};
		}
	};
	_ret
};

// Creates a trigger...
// Ex: [getPos Player, [100,200,33,True], ["WEST", "EAST D", true], ["this", "hint 'trigger on';", "hint 'trigger off';"]] call XfCreateTrigger
XfCreateTrigger = {
	private ["_pos", "_trigarea", "_trigact", "_trigstatem", "_trigger"];
	_pos = _this select 0;
	_trigarea = _this select 1;
	_trigact = _this select 2;
	_trigstatem = _this select 3;
	_trigger = createTrigger ["EmptyDetector" ,_pos];
	_trigger setTriggerArea _trigarea;
	_trigger setTriggerActivation _trigact;
	_trigger setTriggerStatements _trigstatem;
	If (count _this > 4) then {
		If (typename(_this select 4) == "STRING") then { _trigger setTriggerText (_this select 4); };
	};
	_trigger
};

// Returns the Var attached to the given vehicle.
// Ex:  [_veh, "MyVar", "DefaultValue"] call XfGetVar
XfGetVar = {
	private ["_oReturn","_vVehicle","_sVarName","_oDefaultValue"];
	_vVehicle = _this select 0;
	_sVarName = _this select 1;
	_oDefaultValue = _this select 2;
	_oReturn = _oDefaultValue;
	if ((!isNil ("_vVehicle")) AND (_sVarName != "")) then {
		_oReturn = (_vVehicle) getVariable (_sVarName);
	};
	if (isNil "_oReturn") then {_oDefaultValue} else {_oReturn}
};


XfArraySubSelect = {
	/************************************************************
		Subarray Select
		By Andrew Barron

	Returns a sub-selection of the passed array. There are various
	methods the sub-array can be determined.

	Parameters: [array, beg, <end>]
	Returns: subarray

	array - Array to select sub array from.
	beg - Index of array to begin sub-array. If negative, index is
		counted from the end of array.
	end - Optional. Index of array to end the sub-array. If ommitted,
		remainder of the array will be selected. If negative, it
		specifies the length of the sub-array (in absolute form).

	Examples:

		_array = ["a","b",true,3,8];
		[_array, 2] call X_fnc_subSelect; //returns [true,3,8]
		[_array, -2] call X_fnc_subSelect; //returns [3,8]
		[_array, 1, 3] call X_fnc_subSelect; //returns ["b",true,3]
		[_array, 1, -2] call X_fnc_subSelect; //returns ["b",true]

	************************************************************/

	private ["_ary","_beg","_len","_end","_ret","_i"];
	_ret = [];
	_ary = _this select 0;
	_len = (count _ary)-1;
	_beg = _this select 1;
	if(_beg < 0) then {_beg = _len + _beg + 1};
	_end = if(count _this > 2) then {_this select 2} else {_len};
	if(_end < 0) then {_end = _beg - _end - 1};
	if(_end > _len) then {_end = _len};
	for "_i" from _beg to _end do {_ret set [count _ret, _ary select _i]};
	_ret
};

XfArrayInsert = {
	/************************************************************
		Array Insert
		By Andrew Barron

	Parameters: [base array, insert array, index]
	Returs: [array]

	Inserts the elements of one array into another, at a specified
	index.

	Neither arrays are touched by reference, a new array is returned.

	Example: [[0,1,2,3,4], ["a","b","c"], 1] call X_fnc_arrayInsert
	Returns: [0,"a","b","c",1,2,3,4]
	************************************************************/

	private ["_baseArray","_toInsert","_index","_ret"];
	_baseArray = _this select 0;
	_toInsert = _this select 1;
	_index = _this select 2;
	if(_index > 0) then {
		_ret = [_baseArray, 0, _index-1] call XfSubSelect;
		[_ret, _toInsert] call XfArrayPushStack;
	} else {
		_ret = _toInsert;
	};
	[_ret, [_baseArray, _index] call XfSubSelect] call XfArrayPushStack;
	_ret
};

// Converts X/Y coordinates to GPS coordinates in the GRID format 0120345
XfGPSCoords = {
	_xmap = _this select 0;
	_ymap = _this select 1;
	_gpsX = floor (_xmap / 100);
	_compX = "";
	if (_gpsX < 0) then { _gpsX = 1000 + _gpsX };
	if (_gpsX < 100) then { _compX = "0" };
	if (_gpsX < 10) then { _compX = "00" };
	// Adjusting offests depending on the world
	_wd = worldName;
	_zeroY = 15260;
	_coefdir = 1;
	if (_wd == "Chernarus") then {
		_zeroY = 15260;
		_coefdir = 1;
	};
	if (_wd == "Utes") then {
		_zeroY = 5020;
		_coefdir = 1;
	};
	_gpsY = floor ((_zeroY - (_coefdir * _ymap) + 100) / 100);
	_compY = "";
	if (_gpsY < 0) then { _gpsY = 1000 + _gpsY };
	if (_gpsY < 100) then {_compY = "0" };
	if (_gpsY < 10) then {_compY = "00" };
	_gpscoords = format["%1%2%3%4",_compX,_gpsX,_compY,_gpsY];
	_gpscoords;
};

/// @EXAMPLE [_type, _grp, _pos, _dist, _init, _rank, _skill] call XfCreateUnit;
XfCreateUnit = {
	private ["_unit","_units","_grp","_pos","_type","_init","_rank"];
	_type = _this select 0;
	_grp = _this select 1;
	_pos = _this select 2;
	_dist = 0;
	_init = "";
	_rank = "corporal";
	_new_pos = [];
	_skill = (call XfGetUnitSkill);
	if (count _this > 3) then { _dist = _this select 3; };
	if (count _this > 4) then { _init = _this select 4; };
	if (count _this > 5) then { _rank = _this select 5; };
	if (count _this > 6) then { _skill = _this select 6; };
	if (_dist > 0) then {
		_new_pos = _pos findEmptyPosition[ 1 , _dist , _type];
		if (count _new_pos > 0) then { _pos = _new_pos; };
	};
	_unit = objNull;
	_units = units _grp;
	if (isnil "_units") then { _units = []; };			
	diag_log Format["(%1)[%2]: %3: %4",diag_tickTime,"commonfunctions.sqf","XfCreateUnit",[_type,_grp,_pos,_dist,_init,_rank,_skill,_units]];
	_type createUnit [ _pos, _grp, _init, _skill, _rank];
	{ if (!(_x in _units)) exitWith{_unit = _x;};
	} foreach (units _grp);
	diag_log Format["(%1)[%2]: %3: %4",diag_tickTime,"commonfunctions.sqf","XfCreateUnit",[_unit, typeof _unit, side _unit, group _unit, units _grp]];
	_unit
};

g_bCommonFuncsCompiled = true;
